<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	<title>进阶：19、混合</title>
	<script type="text/javascript" src="./js/vue.js"></script>
</head>
<body>
	<div id="app1"></div>
	<div id="app2"></div>
	<div id="app3"></div>	

	<script type="text/javascript">
		// ---------------------------- 基础 ------------------------------
		// 查阅一下vue的API，选项里的mixins就是混合，mixins的值就是选项
		// 比如mixins: { 
		// 		created: function(){
		// 		     // 执行一些操作	
		// 		}
		// }
		// 
		// 那么在某个vue实例中加了这个mixins选项的话，如下面所示：
		// new Vue({
		// 		el: xxx,
		// 		data: xxx,
		// 		mixins: {
		// 			created: function(){
		// 				// 执行一些操作
		// 			}
		// 		}
		// })
		// 
		// 效果等同于：
		// new Vue({
		// 		el: xxx,
		// 		data: xxx,
		// 		created: function(){
		// 			// 执行一些操作
		// 		}
		// })
		// 
		// 写个实例试试
		var myMixins = {
			created: function(){
				alert('demo1: created')
			}
		}
		var vm1 = new Vue({
			el: '#app1',
			mixins: [myMixins]
		})


		// ---------------------------- 选项合并 -----------------------------
		// 在上面的例子中vm对象里并没有声明created这个钩子的回调函数
		// 如果有的话，会发生什么？结果是先调用混合对象钩子的回调，再调用对象内
		// 选项声明的回调，这就是选项合并
		// 
		// 实例demo:
		var testMixins = {
			created: function(){
				alert('demo2: 我是混合对象里的回调')
			}
		}
		var vm2 = new Vue({
			el: '#app2',
			created: function(){
				alert('demo2: 我是组件里的回调')
			},
			mixins: [testMixins]
		})

		// 经过上面的测试，我们知道了如果选项内容是一个回调函数，那么先调用混合对象
		// 的回调函数，再调用组件的回调函数，如果选项内容是一个对象呢？
		// 合并的策略是优先选取组件的对象内容，抛弃同名混合对象的对象内容
		// 
		// 实例demo:
		var objMixins = {
			methods: {
				foo: function(){
					console.log('demo3: foo')
				},
			    conflicting: function () {
			      console.log('demo3: from mixin')
			    }				
			}
		}
		var vm3 = new Vue({
		  mixins: [objMixins],
		  methods: {
		    bar: function () {
		      console.log('demo3: bar')
		    },
		    conflicting: function () {
		      console.log('demo3: from self')
		    }
		  }
		})	
		// 测试vm3实例的方法
		vm3.foo()
		vm3.bar()
		vm3.conflicting()    
		// 输出结果为：
		// => demo3: foo
		// => demo3: bar
		// => demo3: from self
		// 第三个输出的结果验证规律
		

		// -------------------------------- 全局混合 ----------------------------------
		// 其实全局和局部的使用手法，在前面介绍的很多vue的特性中，大家都见识很多了，作用
		// 域不同。一般Vue.xxx()都是属于全局注册或使用的手法，在组件内选项声明的属于局部
		// 使用和注册。
		// 
		// 实例demo:
		// 注册全局混合，为自定义的选项 'myOption' 注入一个处理器。
		// 注意这里注册的全局混合队所有的vue实例都有效
		Vue.mixin({
			created: function () {
				// $options属于vue实例的实例属性
				// 用于当前 Vue 实例的初始化选项。需要在选项中包含自定义属性时会有用处
				var myOption = this.$options.myOption
				if (myOption) {
				    console.log(myOption)
				}
			}
		})
		new Vue({
		  	myOption: 'hello!'
		})
		// 一旦使用全局混合对象，将会影响到 所有 之后创建的 Vue 实例。使用恰当时，可以为自定义对象注入处理逻辑。
		// PS.谨慎使用全局混合对象，因为会影响到每个单独创建的 Vue 实例（包括第三方模板）。大多数情况下，只应当应用于自定义选项，就像上面示例一样。 也可以将其用作 Plugins 以避免产生重复应用
		

		// ------------------------- 自定义选项混合策略 ---------------------------
		// 在上面的例子中，介绍了值属于回调函数还有对象的混合选项的合并策略
		// 即回调会按先混合后组件的顺序执行，而对象在混合和组件中若同名组件覆盖混合
		// 对于自定义的选项来说，合并的策略也是第二种，但如果我们想自定义自定义选项
		// 的合并逻辑，可以向 Vue.config.optionMergeStrategies 添加一个函数：
		// 
		// # Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {
		// # 	return mergedVal
		// # }
		// 
		// 来测试一下这玩意怎么用的！
		Vue.config.optionMergeStrategies.testOption = function(toVal, fromVal){
			console.log(toVal, fromVal)
			return toVal
		}
		var customMixins = {
			testOption: '我是混合里的自定义选项值'
		}
		var vm4 = new Vue({
			mixins: [customMixins],
			testOption: '我是组件里自定义选项值'
		})
		console.log(vm4.$options.testOption)
		// 测试的结果是，暂时没看懂囧。怎么个自定义法？
		// => undefined "我是混合里的自定义选项值"     // 147行的console
		// => undefined "我是组件里自定义选项值"       // 147行的console
		// => undefined                                // 157行的console
		
		// 对于大多数对象选项，可以使用 methods 的合并策略:
		// var strategies = Vue.config.optionMergeStrategies
		// strategies.myOption = strategies.methods
		// 
		// 测试一下：
		var strategies = Vue.config.optionMergeStrategies
		strategies.testOption2 = strategies.methods
		var customMixins2 = {
			testOption2: { 
				a: '我是混合里的自定义选项值'
			}
		}
		var vm5 = new Vue({
			mixins: [customMixins2],
			testOption2: {
				a: '我是组件里自定义选项值'
			}
		})		
		console.log(vm5.$options.testOption2)
		// 输出是这样子，合并策略生效
		// Object {a: "我是组件里自定义选项值"}
	</script>
</body>
</html>